﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Xml.Serialization;

using MiniTwitter.Extensions;
using MiniTwitter.Input;
using MiniTwitter.Log;

namespace MiniTwitter.Properties
{
    [Serializable]
    [XmlRoot("MiniTwitter")]
    public class Settings : PropertyChangedBase
    {
        private Settings()
        {
            EnableAutoRefresh = true;
            RefreshTick = 1;
            RefreshReplyTick = 10;
            RefreshMessageTick = 15;
            TimelineStyle = TimelineStyle.Standard;
            IsIconVisible = true;
            SortCategory = ListSortCategory.CreatedAt;
            SortDirection = ListSortDirection.Descending;
            EnablePopup = true;
            PopupCloseTick = 15;
            EnableTweetFooter = false;
            TweetFooter = "*MT*";
            EnableHeartMark = true;
            PopupOnlyFavorite = false;
            PopupOnlyNotActive = false;
            PopupLocation = PopupLocation.Auto;
            EnableNotifyIcon = true;
	
			#region added by yuki.
			fontName = "メイリオ";
			fontSize = 14;
			fontWeight = "Normal";
			ShowInTaskbar = true;
			IsEnableSearchTimeline = false;
			SearchString = "";
			#endregion
		}

        /// <summary>
        /// ウィンドウの位置
        /// </summary>
        public Point Location { get; set; }

        /// <summary>
        /// ウィンドウのサイズ
        /// </summary>
        public Size Size { get; set; }

        /// <summary>
        /// ウィンドウの状態
        /// </summary>
        public WindowState WindowState { get; set; }

        /// <summary>
        /// ユーザー名
        /// </summary>
        public string Username { get; set; }

        /// <summary>
        /// パスワード
        /// </summary>
        public string Password { get; set; }

        /// <summary>
        /// 自動更新を有効にする
        /// </summary>
        public bool EnableAutoRefresh { get; set; }

        /// <summary>
        /// フレンドタイムライン自動更新間隔
        /// </summary>
        public int RefreshTick { get; set; }

        /// <summary>
        /// 返信タイムライン自動更新間隔
        /// </summary>
        public int RefreshReplyTick { get; set; }

        /// <summary>
        /// ダイレクトメッセージ自動更新間隔
        /// </summary>
        public int RefreshMessageTick { get; set; }

        /// <summary>
        /// プロキシを使用する
        /// </summary>
        public bool UseProxy { get; set; }

        /// <summary>
        /// Internet Explorer のプロキシ設定を使用する
        /// </summary>
        public bool UseIEProxy { get; set; }

        /// <summary>
        /// プロキシサーバのアドレス
        /// </summary>
        public string ProxyAddress { get; set; }

        /// <summary>
        /// プロキシサーバのポート番号
        /// </summary>
        public string ProxyPortNumber { get; set; }

        /// <summary>
        /// プロキシのログインユーザー名
        /// </summary>
        public string ProxyUsername { get; set; }

        /// <summary>
        /// プロキシのログインパスワード
        /// </summary>
        public string ProxyPassword { get; set; }

        private TimelineStyle timelineStyle;

        /// <summary>
        /// タイムラインの表示スタイル
        /// </summary>
        public TimelineStyle TimelineStyle
        {
            get { return timelineStyle; }
            set
            {
                if (timelineStyle != value)
                {
                    timelineStyle = value;
                    OnPropertyChanged("TimelineStyle");
                }
            }
        }

        private bool isIconVisible;

        /// <summary>
        /// アイコンを表示する
        /// </summary>
        public bool IsIconVisible
        {
            get { return isIconVisible; }
            set
            {
                if (isIconVisible != value)
                {
                    isIconVisible = value;
                    OnPropertyChanged("IsIconVisible");
                }
            }
		}

		#region added by yuki.
		private string fontName;

		/// <summary>
		/// 表示するフォント
		/// </summary>
		public string FontName {
			get { return fontName; }
			set {
				if (fontName != value) {
					fontName = value;
					OnPropertyChanged("FontName");
				}
			}
		}

		[XmlIgnore]
		public List<string> AllFontFamily {
			get {
				return System.Drawing.FontFamily.Families.Select(font => font.Name).ToList();
			}
		}

		private int fontSize;
		public int FontSize {
			get { return fontSize; }
			set {
				if (fontSize != value) {
					fontSize = value;
					OnPropertyChanged("FontSize");
				}
			}
		}

		private string fontWeight;
		public string FontWeight {
			get { return fontWeight; }
			set {
				if (fontWeight != value) {
					fontWeight = value;
					OnPropertyChanged("FontWeight");
				}
			}
		}

		private bool showInTaskbar;
		public bool ShowInTaskbar {
			get { return showInTaskbar; }
			set {
				if (showInTaskbar != value) {
					showInTaskbar = value;
					OnPropertyChanged("ShowInTaskbar");
				}
			}
		}

		private bool isEnableSearchTimeline;
		public bool IsEnableSearchTimeline {
			get { return isEnableSearchTimeline; }
			set {
				if (isEnableSearchTimeline != value) {
					isEnableSearchTimeline = value;
					OnPropertyChanged("IsEnableSearchTimeline");
				}
			}
		}

		private bool isSearchOnlyJapanese; //検索結果を日本語に限定する
		public bool IsSearchOnlyJapanese {
			get { return isSearchOnlyJapanese; }
			set {
				if (isSearchOnlyJapanese != value) {
					isSearchOnlyJapanese = value;
					OnPropertyChanged("IsSearchOnlyJapanese");
				}
			}
		}

		private string searchString;
		public string SearchString {
			get { return searchString; }
			set {
				if (searchString != value) {
					searchString = value;
					OnPropertyChanged("SearchString");
				}
			}
		}

		private bool isHideTwitFormWhenAppStart;
		public bool IsHideTwitFormWhenAppStart {
			get { return isHideTwitFormWhenAppStart; }
			set {
				if (isHideTwitFormWhenAppStart != value) {
					isHideTwitFormWhenAppStart = value;
					OnPropertyChanged("IsHideTwitFormWhenAppStart");
				}
			}
		}

		private bool isCloseTwitFormWhenUpdateStatus;
		public bool IsCloseTwitFormWhenUpdateStatus {
			get { return isCloseTwitFormWhenUpdateStatus; }
			set {
				if (isCloseTwitFormWhenUpdateStatus != value) {
					isCloseTwitFormWhenUpdateStatus = value;
					OnPropertyChanged("IsCloseTwitFormWhenUpdateStatus");
				}
			}
		}
		#endregion  added by yuki.

		private ListSortCategory sortCategory;

        public ListSortCategory SortCategory
        {
            get { return sortCategory; }
            set
            {
                if (sortCategory != value)
                {
                    sortCategory = value;
                    OnPropertyChanged("SortCategory");
                }
            }
        }

        private ListSortDirection sortDirection;

        public ListSortDirection SortDirection
        {
            get { return sortDirection; }
            set
            {
                if (sortDirection != value)
                {
                    sortDirection = value;
                    OnPropertyChanged("SortDirection");
                }
            }
        }

        public bool EnablePopup { get; set; }

        public bool PopupOnlyNotActive { get; set; }

        public bool PopupOnlyFavorite { get; set; }

        public int PopupCloseTick { get; set; }

        private PopupLocation _popupLocation;

        public PopupLocation PopupLocation
        {
            get { return _popupLocation; }
            set
            {
                _popupLocation = value;
                OnPropertyChanged("PopupLocation");
            }
        }

        public string Theme { get; set; }

        public bool EnableLog { get; set; }

        public LogFormat LogFormat { get; set; }

        public string LogFileName { get; set; }

        public bool EnableTweetFooter { get; set; }

        public string TweetFooter { get; set; }

        [XmlArray("TweetFooterHistory")]
        public string[] TweetFooterHistoryInternal
        {
            get { return TweetFooterHistory.Count != 0 ? TweetFooterHistory.ToArray() : null; }
            set { TweetFooterHistory = new ObservableCollection<string>(value ?? Enumerable.Empty<string>()); }
        }

        [XmlIgnore]
        public ObservableCollection<string> TweetFooterHistory { get; private set; }

        public bool EnableHeartMark { get; set; }

        public bool EnableUnreadManager { get; set; }

        public bool EnableNotifyIcon { get; set; }

        public string BrowserPath { get; set; }

        [XmlArray("Timelines")]
        public Timeline[] TimelinesInternal
        {
            get { return Timelines.Count != 0 ? Timelines.ToArray() : null; }
            set { Timelines = new ObservableCollection<Timeline>(value ?? Enumerable.Empty<Timeline>()); }
        }

        [XmlIgnore]
        public ObservableCollection<Timeline> Timelines { get; private set; }

        public string KeyMapping { get; set; }

        [XmlArray("KeyBindings")]
        public KeyBinding[] KeyBindingsInternal
        {
            get { return KeyBindings.Count != 0 ? KeyBindings.ToArray() : null; }
            set { KeyBindings = new ObservableCollection<KeyBinding>(value ?? Enumerable.Empty<KeyBinding>()); }
        }
        
        [XmlIgnore]
        public ObservableCollection<KeyBinding> KeyBindings { get; private set; }

        [XmlArray("SoundBindings")]
        public SoundBinding[] SoundBindingsInternal
        {
            get { return SoundBindings.Count != 0 ? SoundBindings.ToArray() : null; }
            set { SoundBindings = new ObservableCollection<SoundBinding>(value ?? Enumerable.Empty<SoundBinding>()); }
        }

        [XmlIgnore]
        public ObservableCollection<SoundBinding> SoundBindings { get; private set; }

        [XmlArray("KeywordBindings")]
        public KeywordBinding[] KeywordBindingsInternal
        {
            get { return KeywordBindings.Count != 0 ? KeywordBindings.ToArray() : null; }
            set { KeywordBindings = new ObservableCollection<KeywordBinding>(value ?? Enumerable.Empty<KeywordBinding>()); }
        }

        [XmlIgnore]
        public ObservableCollection<KeywordBinding> KeywordBindings { get; private set; }

        [XmlIgnore]
        public Regex FavoriteRegex { get; set; }

        [XmlIgnore]
        public Regex IgnoreRegex { get; set; }

        public void InitializeKeywordRegex()
        {
            var favorites = KeywordBindings.Where(p => p.IsEnabled && p.Action == KeywordAction.Favorite).Select(p => Regex.Escape(p.Keyword)).ToArray();
            FavoriteRegex = favorites.Length > 0 ? new Regex(string.Join("|", favorites)) : null;

            var ignores = KeywordBindings.Where(p => p.IsEnabled && p.Action == KeywordAction.Ignore).Select(p => Regex.Escape(p.Keyword)).ToArray();
            IgnoreRegex = ignores.Length > 0 ? new Regex(string.Join("|", ignores)) : null;
        }

        private void InitializeCollections()
        {
            if (TweetFooterHistory == null)
            {
                TweetFooterHistory = new ObservableCollection<string>();
            }
            if (Timelines == null)
            {
                Timelines = new ObservableCollection<Timeline>();
            }
            if (KeyBindings == null)
            {
                KeyBindings = new ObservableCollection<KeyBinding>();
            }
            if (SoundBindings == null)
            {
                SoundBindings = new ObservableCollection<SoundBinding>()
                {
                    new SoundBinding { Action = SoundAction.Status },
                    new SoundBinding { Action = SoundAction.Message },
                    new SoundBinding { Action = SoundAction.Reply },
                };
            }
            if (KeywordBindings == null)
            {
                KeywordBindings = new ObservableCollection<KeywordBinding>();
            }
            InitializeKeywordRegex();
        }

        private static string BaseDirectory { get; set; }

        public static Settings Default { get; private set; }
        
        public static void Load(string directory)
        {
            try
            {
                BaseDirectory = directory;
                using (var stream = File.Open(Path.Combine(BaseDirectory, @"Preference.xml"), FileMode.Open))
                {
                    Default = Serializer<Settings>.Deserialize(stream);
                }
                if (!Default.Password.IsNullOrEmpty())
                {
                    Default.Password = Encoding.ASCII.GetString(Convert.FromBase64String(Default.Password));
                }
                if (Default.RefreshReplyTick > 20)
                {
                    Default.RefreshReplyTick = 10;
                }
            }
            catch
            {
                Default = new Settings();
            }
            // コレクションを初期化
            Default.InitializeCollections();
        }

        public static void Save()
        {
            if (Default == null || BaseDirectory.IsNullOrEmpty())
            {
                return;
            }
            if (!Directory.Exists(BaseDirectory))
            {
                Directory.CreateDirectory(BaseDirectory);
            }
            if (!Default.Password.IsNullOrEmpty())
            {
                Default.Password = Convert.ToBase64String(Encoding.ASCII.GetBytes(Default.Password));
            }
            using (var stream = File.Open(Path.Combine(BaseDirectory, @"Preference.xml"), FileMode.Create, FileAccess.Write, FileShare.None))
            {
                Serializer<Settings>.Serialize(stream, Default);
            }
        }
    }
}
